const RSA = require('./wx_rsa.js');
const littleEndianUtils = require('./little_endian_utils');
import Log from './log.js';
import Vue from 'vue'
// 科新微信小程序的pid和私钥
const PID = 'WX209900100803';
const PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKDgBh1GUTrBkDhqNsLvIuztsFLEwlU4wfG9jHZaVoVsgv3KK5g+bOEGFupicwXW9DGWJX7xN7zqzUBm8SYq1qxtxZ22X3mwjzP6Qgvpn/SfiTH97xsObLaiJ/6J7iClzMnauES0osgUTjuPBz08TD4F/pQBK7BgFXDUFcVUDo7HAgMBAAECgYAWcEjKCoXH8TmhdMcgl2RCscB3OvR0GI+MnUibNWx9/a2jonBEMujS1huaI5MxjFLRG8UtGI4SrplkUzdtgGoiuCwmruwz3GuGAYaRq4ob7oMzMw2ZqA3KDm4ziOkelX2bSX2VQJjLGAFeuhTq25pXvUrX6X/QA7Lb8INsaeG8OQJBAMuwUO2QDmZDedGPWiMfOhN2V4fhCDSCmr3yc1KMT7bsRu9xAw407eTkVLo1OhUdoIG6xRTKxg1mZATFcpKD7K0CQQDKMOO7ppfGGSMRIQ8zB/R5ON16ip+BZ25rBXWCQEBg8FdBZkQU4dxKkPL5IC2KAjBOAGSTfwj5kr8VZt6xIEPDAkEAsb5BUJzlw91b3z+t03o7bqJVTZBUXaYerGR2t/ES2rgiSm2e0fXkJloNiZRLBAQffTVjJ3qvCyBvZS57hVkz3QJAFZVqehmqkgcU6zswOC5dNqOPYQlzRYkZDGukw6bAOJjvd5fHJMOHlJ4skdORiO364hjAo84n0xyLMWmt1BKxqQJBAJYFDb5uC0mcfEBL76lwottfOf6MbpLMuXPCISFHy4lrIHltMJYzDecIXVa2av3ygWR4xwM3+Ym4YbZHPTCjV+c=
-----END PRIVATE KEY-----`
const EARTH_RADIUS = 6378137.0; //单位M
const PI = Math.PI;
const qqmapkey = 'AZ3BZ-LK7CU-V35VW-2JNT3-IDOZ3-77B4V'; //使用在腾讯位置服务申请的keye
const amapkey = '41b051d44ed4547c98ba0c2e8dfcb568'; //高德key
const codeMap = {
	'-2': '未知错误',
	'-1': '蓝牙已连接',
	'10000': '未初始化蓝牙适配器',
	'10001': '蓝牙未打开',
	'10002': '未找到指定设备',
	'10003': '连接失败',
	'10004': '未找到指定服务',
	'10005': '未找到指定特征',
	'10006': '当前连接已断开',
	'10007': '当前特征不支持此操作',
	'10008': '其余所有系统上报的异常',
	'10009': '系统版本低于 4.3 不支持 BLE',
	'10012': '连接超时',
	'10013': '连接deviceId为空或者是格式不正确',
	'90001': '请查看是否打开位置',
	'99990': '获取系统信息失败',
	'99991': '用户未授权小程序使用定位服务',
	'99992': 'DFU升级缺少serviceId',
	'99993': 'DFU升级缺少characteristicId90001',
	'99994': 'DFU升级响应收到意外的返回码',
	'99995': 'DFU升级数据解析结果不成功',
	'99996': 'DFU升级数据解析为匹配到相应的CONTROL OPCODES',
	'99999': 'MTU 值设置不正确'
}
const BASE_POS = 3;
const CALCULATE_CHECKSUM_RESPONSE_FIELD = {
	OFFSET: BASE_POS + 0,
	CRC32: BASE_POS + 4,
};
const SELECT_RESPONSE_FIELD = {
	MAXIMUM_SIZE: BASE_POS + 0,
	OFFSET: BASE_POS + 4,
	CRC32: BASE_POS + 8,
};

let isLoading = false;

// 加签
const getSign = source => {
	let sign_rsa = new RSA.RSAKey();
	sign_rsa = RSA.KEYUTIL.getKey(PRIVATE_KEY);
	let sign = sign_rsa.signString(source, 'sha1');
	sign = RSA.hex2b64(sign); // hex 转 b64
	// console.log("加签结果：" + sign)
	return sign;
}

// RSA解密（对开关锁时后台返的已加密的报文进行解密）
const decrypt = (openLock_cmd, successCb) => {
	var decrypt_rsa = new RSA.RSAKey();
	decrypt_rsa = RSA.KEYUTIL.getKey(PRIVATE_KEY, null, 'pkcs8prv');
	// console.log('解密RSA:')
	// console.log(decrypt_rsa)
	openLock_cmd = RSA.b64tohex(openLock_cmd);
	let decStr = decrypt_rsa.decrypt(openLock_cmd);
	// console.log("解密结果：" + decStr)
	successCb(decStr);
}

const getOpenTime = () => {
	var date = new Date();
	var year = date.getFullYear();
	var month = date.getMonth() + 1;
	var day = date.getDate();
	var hour = date.getHours();
	var minute = date.getMinutes();
	var second = date.getSeconds();
	var res = year + '-' + month + '-' + day + ' ' + hour + ':' + minute +
		':' + second;
	return res;
}

const add0 = (m) => {
	return m < 10 ? '0' + m : m
}

const timeFormat = (timestamp) => {
	//timestamp是整数，否则要parseInt转换,不会出现少个0的情况
	var time = new Date(timestamp);
	var year = time.getFullYear();
	var month = time.getMonth() + 1;
	var date = time.getDate();
	var hours = time.getHours();
	var minutes = time.getMinutes();
	var seconds = time.getSeconds();
	return year + '年' + add0(month) + '月' + add0(date) + '日 ' + add0(hours) + ':' + add0(minutes) + ':' + add0(
		seconds);
}


const getOpenId = ()=>{
	return new Promise((resolve,reject)=>{
		uni.getStorage({
			key:'openId',
			success:res=>{
				resolve(res.data);
			},
			fail:()=>{
				resolve('')
			}
		})
	})
}

const getSignState=()=>{
	return new Promise((resolve,reject)=>{
		uni.getStorage({
			key:'signInState',
			success:res=>{
				resolve(res.data)
			},
			fail:()=>{
				resolve('')
			}
		})
	})
}

const createUUID = (len, radix) => {
	const chars = '0123456789'.split('');
	const uuid = [];
	radix = radix || chars.length;
	if (len) {
		for (let i = 0; i < len; i++) {
			uuid[i] = chars[1 | Math.random() * radix];
		}
	}
	return uuid.join('');
}

const toast = (msg, icon = 'none') => {
	uni.showToast({
		title: msg,
		icon: icon,
		duration: 3000
	})
}

const alert = (msg) => {
	uni.showModal({
		title: '温馨提示',
		content: msg,
		showCancel: false,
		confirmText: '确认',
		success: (res) => {
			if (res.confirm) {
				// console.log('用户点击确定')
			} else if (res.cancel) {
				// console.log('用户点击取消')
			}
		}
	})
}

const infotip = (errCode = -2, msg = '', type = 1, duration = 3000) => {
	msg = msg || codeMap[errCode + '']
	switch (type) {
		case 1:
			uni.showModal({
				title: '错误码' + errCode,
				content: msg,
				showCancel: false,
				confirmText: '确认'
			})
			break;
		case 2:
			uni.showToast({
				title: 'errCode:' + errCode + ' ' + msg,
				icon: 'none',
				duration: duration
			})
			break;
	}
}

const getErrMsgByCode = (errCode = -2) => {
	const msg = codeMap[errCode + ''] || '未知错误';
	return msg;
}

const loading = (msg) => {
	isLoading = true;
	uni.showLoading({
		title: msg,
		mask: true,
		success: () => {
			// isLoading = true;
		}
	})
}

const hideLoading = () => {
	if (isLoading) {
		isLoading = false;
		uni.hideLoading({
			success: () => {
				// isLoading = false;
			}
		});
	}
}
/**
 * 将str字符串 每隔length的长度内插入冒号':'
 */
const strInsert = (str, length) => {
	var reg = new RegExp('\\w{1,' + length + '}', 'g');
	let ma = str.match(reg);
	return ma.join(':');
}

const padLeft = (ret, padChar, width) => {
	while (ret.length < width) {
		if (ret.length + padChar.length < width) {
			ret = padChar + ret;
		} else {
			ret = padChar.substring(0, width - ret.length) + ret;
		}
	}
	return ret;
};
const padRight = (ret, padChar, width) => {
	while (ret.length < width) {
		if (ret.length + padChar.length < width) {
			ret += padChar;
		} else {
			ret += padChar.substring(0, width - ret.length);
		}
	}
	return ret;
};
const hexToAscii = (hexCharCodeStr) => {
	var trimedStr = hexCharCodeStr.trim();
	var rawStr =
		trimedStr.substr(0, 2).toLowerCase() === "0x" ?
		trimedStr.substr(2) :
		trimedStr;
	var len = rawStr.length;
	if (len % 2 !== 0) {
		alert("Illegal Format ASCII Code!");
		return "";
	}
	var curCharCode;
	var resultStr = [];
	for (var i = 0; i < len; i = i + 2) {
		curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
		resultStr.push(String.fromCharCode(curCharCode));
	}
	return resultStr.join("");
}

const myStringtoHex = (str) => {
	str = str.toLowerCase();
	let newBuffer = new ArrayBuffer(str.length / 2);
	let hexBuffer = new Uint8Array(newBuffer, 0);
	let h = 0,
		l = 0;
	for (let i = 0; i < str.length / 2; i++) {
		h = str.charCodeAt(2 * i);

		l = str.charCodeAt(2 * i + 1);
		if (48 <= h && h <= 57) {
			h = h - 48;
		} else {
			h = h - 97 + 10;
		}
		if (48 <= l && l <= 57) {
			l = l - 48;
		} else {
			l = l - 97 + 10;
		}
		hexBuffer[i] = h * 16 + l;
	}
	return hexBuffer;
}
/**
 * 字符串 ascii码转16进制
 */
const asciiToHex = (str) => {
	if (str === "") {
		return "";
	} else {
		var hexCharCode = [];
		for (var i = 0; i < str.length; i++) {
			hexCharCode.push((str.charCodeAt(i)).toString(16));
		}
		return hexCharCode.join("");
	}
}

// 设置顶部导航栏标题
const setNavTitle = (title) => {
	uni.setNavigationBarTitle({
		title
	})
}

/**
 * 异或值计算
 */
const calculatXor = (str) => {
	let sum = 0;
	const ss = str.split(" ")
	for (var i = 0; i < ss.length; i++) {
		if (ss[i] == "") {
			continue;
		}
		sum = sum ^ parseInt(ss[i], 16);
	}
	return sum.toString(16);
}

const setUserInfo = (res) => {
	const userInfo = res;
	// 存储sessionId
	uni.setStorageSync('openId', userInfo.userDto.openId)
	uni.setStorageSync('userId', userInfo.userDto.userId)
	uni.setStorageSync('mobile', userInfo.userDto.mobile)
	uni.setStorageSync('name', userInfo.userDto.name)

	Vue.prototype.$userInfo.openId = userInfo.userDto.openId;
	Vue.prototype.$userInfo.userId = userInfo.userDto.userId;
	Vue.prototype.$userInfo.mobile = userInfo.userDto.mobile;
	Vue.prototype.$userInfo.name = userInfo.userDto.name;
}


const formatTime = (number, format) => {
	var formateArr = ['Y', 'M', 'D', 'h', 'm', 's'];
	var returnArr = [];

	var date = new Date(number * 1000);
	returnArr.push(date.getFullYear());
	returnArr.push(formatNumber(date.getMonth() + 1));
	returnArr.push(formatNumber(date.getDate()));

	returnArr.push(formatNumber(date.getHours()));
	returnArr.push(formatNumber(date.getMinutes()));
	returnArr.push(formatNumber(date.getSeconds()));

	for (var i in returnArr) {
		format = format.replace(formateArr[i], returnArr[i]);
	}
	return format;
}

const formatNumber = (n) => {
	n = n.toString();
	return n[1] ? n : '0' + n;
}


const Base64 = {
	_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
	encode: function(e) {
		var t = "";
		var n, r, i, s, o, u, a;
		var f = 0;
		e = Base64._utf8_encode(e);
		while (f < e.length) {
			n = e.charCodeAt(f++);
			r = e.charCodeAt(f++);
			i = e.charCodeAt(f++);
			s = n >> 2;
			o = (n & 3) << 4 | r >> 4;
			u = (r & 15) << 2 | i >> 6;
			a = i & 63;
			if (isNaN(r)) {
				u = a = 64
			} else if (isNaN(i)) {
				a = 64
			}
			t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) +
				this._keyStr.charAt(u) + this._keyStr.charAt(a)
		}
		return t
	},
	decode: function(e) {
		var t = "";
		var n, r, i;
		var s, o, u, a;
		var f = 0;
		e = e.replace(/[^A-Za-z0-9+/=]/g, "");
		while (f < e.length) {
			s = this._keyStr.indexOf(e.charAt(f++));
			o = this._keyStr.indexOf(e.charAt(f++));
			u = this._keyStr.indexOf(e.charAt(f++));
			a = this._keyStr.indexOf(e.charAt(f++));
			n = s << 2 | o >> 4;
			r = (o & 15) << 4 | u >> 2;
			i = (u & 3) << 6 | a;
			t = t + String.fromCharCode(n);
			if (u != 64) {
				t = t + String.fromCharCode(r)
			}
			if (a != 64) {
				t = t + String.fromCharCode(i)
			}
		}
		t = Base64._utf8_decode(t);
		return t
	},
	_utf8_encode: function(e) {
		// e = e.replace(/rn/g, "n");
		var t = "";
		for (var n = 0; n < e.length; n++) {
			var r = e.charCodeAt(n);
			if (r < 128) {
				t += String.fromCharCode(r)
			} else if (r > 127 && r < 2048) {
				t += String.fromCharCode(r >> 6 | 192);
				t += String.fromCharCode(r & 63 | 128)
			} else {
				t += String.fromCharCode(r >> 12 | 224);
				t += String.fromCharCode(r >> 6 & 63 | 128);
				t += String.fromCharCode(r & 63 | 128)
			}
		}
		return t
	},
	_utf8_decode: function(e) {
		var t = "";
		var n = 0;
		var r = c1 = c2 = 0;
		while (n < e.length) {
			r = e.charCodeAt(n);
			if (r < 128) {
				t += String.fromCharCode(r);
				n++
			} else if (r > 191 && r < 224) {
				c2 = e.charCodeAt(n + 1);
				t += String.fromCharCode((r & 31) << 6 | c2 & 63);
				n += 2
			} else {
				c2 = e.charCodeAt(n + 1);
				c3 = e.charCodeAt(n + 2);
				t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 &
					63);
				n += 3
			}
		}
		return t
	}
}
// 字符串转指定长度的数组
const strSplitToArr = function(str, len) {
	let arr = [];
	let index = 0;
	while (index < str.length) {
		arr.push(str.slice(index, index += len));
	}
	return arr;
}
// 16进制字符串转成array buffer
const hexToBytes = function(str) {
	const typedArray = new Uint8Array(str.match(/[\da-f]{2}/gi).map((h) => {
		return parseInt(h, 16)
	}))
	return typedArray.buffer
}
// 16进制转字符串
const ab2hex = function(buffer) {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function(bit) {
			return (`00${bit.toString(16)}`).slice(-2)
		}
	)
	return hexArr.join('')
}

// array buffer 转成十六进制
const arrayBuffer2Hex = (buffer) => {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function(bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('')
}
//  array buffer 转成字符串
const arrayBufferToString = (buffer, arr) => {
	let str = '';
	const bytes = new Uint8Array(buffer);
	const len = bytes.byteLength;
	let count = 0;
	let total = 0x00;
	for (let i = 0; i < len; i++) {
		const bit = bytes[i];
		const hex = ('00' + bit.toString(16)).slice(-2);
		str += hex;
		total = total + (+('0x' + hex).toString(16)); // 将每个16进制字节相加
		count++
		if (count == 64) {
			count = 0;
			arr.push(str);
			str = '';
		} else if (i == len - 1) {
			// 最后一包 不足64字节补上的ff 要参与累积和校验值的计算中
			const len = str.length;
			const fillLen = (128 - len) / 2;
			for (let i = 0; i < fillLen; i++) {
				total = total + (+('0xff').toString(16))
			}
			arr.push(str)
		}
	}
	return (total).toString(16);
}
const stringToArrayBuffer = function(str) {
	let bytes = new Array();
	let len, c;
	len = str.length;
	for (let i = 0; i < len; i++) {
		c = str.charCodeAt(i);
		if (c >= 0x010000 && c <= 0x10FFFF) {
			bytes.push(((c >> 18) & 0x07) | 0xF0);
			bytes.push(((c >> 12) & 0x3F) | 0x80);
			bytes.push(((c >> 6) & 0x3F) | 0x80);
			bytes.push((c & 0x3F) | 0x80);
		} else if (c >= 0x000800 && c <= 0x00FFFF) {
			bytes.push(((c >> 12) & 0x0F) | 0xE0);
			bytes.push(((c >> 6) & 0x3F) | 0x80);
			bytes.push((c & 0x3F) | 0x80);
		} else if (c >= 0x000080 && c <= 0x0007FF) {
			bytes.push(((c >> 6) & 0x1F) | 0xC0);
			bytes.push((c & 0x3F) | 0x80);
		} else {
			bytes.push(c & 0xFF);
		}
	}
	let array = new Int8Array(bytes.length);
	for (let i = 0; i <= bytes.length; i++) {
		array[i] = bytes[i];
	}
	return array.buffer;
}

const formater4length = function(data) {
	data = data.toString(16)
	if (data.length == 3) {
		data = "0" + data
	} else if (data.length == 2) {
		data = "00" + data
	} else if (data.length == 1) {
		data = "000" + data
	}
	var dataArray = new Array();
	dataArray.push("0x" + data.slice(2))
	dataArray.push("0x" + data.slice(0, 2))
	console.log("hexstr:" + dataArray)
	return dataArray;
}

const formatHex = (s) => {
	if (s.indexOf(' ') < 0 && s.length % 2 == 1) {
		s = '0' + s;
	}
	s = s.replace(/(\w{2})(?=[^ ])/gim, "$1 ")
	s = s.replace(/^(\w) /gim, "0$1 ")
	s = s.replace(/ (\w)$/gim, " 0$1")
	s = s.replace(/ (\w) /gim, " 0$1 ")
	s = s.replace(/ (\w) /gim, " 0$1 ")
	s = s.replace(/\s{2,}/gim, " ")
	return s;
}

const bufferFromHex = (hex) => {
	var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h) {
		return parseInt(h, 16)
	}))
	return typedArray.buffer
}

const formater4Length = function(data) {
	data = data.toString(16)
	if (data.length == 3) {
		data = "0" + data
	} else if (data.length == 2) {
		data = "00" + data
	} else if (data.length == 1) {
		data = "000" + data
	}
	const dataArray = new Array();
	dataArray.push("0x" + data.slice(2))
	dataArray.push("0x" + data.slice(0, 2))
	console.log("formater4Length hexstr:" + dataArray)
	return dataArray;
}

const parseResponse = function(resp) {
	let response = new DataView(resp);
	const responseCode = response.getUint8(0); // 返回数据第一位:response code  60:表示成功
	const responseOpCode = response.getUint8(1); // 第二位 是操作命令  也就是响应的是那条命令的操作
	const resultCode = response.getUint8(2); // 第三位 指令的执行结果 01表示成功
	let responseSpecificData;
	if (responseCode !== 0x60) {
		throw new Error({
			code: 99994,
			msg: 'DFU升级响应收到意外的返回码'
		});
	}
	if (resultCode !== 0x01) {
		throw new Error({
			code: 99995,
			msg: 'DFU升级数据解析结果不成功'
		});
	}
	switch (responseOpCode) {
		case 0x01:
			break;
		case 0x02:
			break;
		case 0x03: //3
			responseSpecificData = {
				offset: littleEndianUtils.littleEndianUInt32(response.getUint32(CALCULATE_CHECKSUM_RESPONSE_FIELD.OFFSET)),
				crc32: littleEndianUtils.littleEndianUInt32(response.getUint32(CALCULATE_CHECKSUM_RESPONSE_FIELD.CRC32)),
			};
			break;
		case 0x04:
			break;
		case 0x06: // 6
			responseSpecificData = {
				maximumSize: littleEndianUtils.littleEndianUInt32(response.getUint32(
					SELECT_RESPONSE_FIELD.MAXIMUM_SIZE)),
				offset: littleEndianUtils.littleEndianUInt32(response.getUint32(SELECT_RESPONSE_FIELD
					.OFFSET)),
				crc32: littleEndianUtils.littleEndianUInt32(response.getUint32(SELECT_RESPONSE_FIELD
					.CRC32)),
			};
			break;
		default:
			throw new Error({
				code: 99996,
				msg: 'DFU升级数据解析为匹配到相应的CONTROL OPCODES'
			});
	}
	return {
		responseCode: responseCode,
		responseOpCode: responseOpCode,
		resultCode: resultCode,
		data: responseSpecificData,
	};
}

export default {
	PID,
	getSign,
	decrypt,
	getOpenTime,
	getOpenId,
	getSignState,
	add0,
	timeFormat,
	createUUID,
	toast,
	alert,
	infotip,
	loading,
	hideLoading,
	strInsert,
	myStringtoHex,
	hexToAscii, // 16进制转ascii
	asciiToHex, // ascii码转16进制
	setNavTitle,
	setUserInfo,
	formatTime,
	formatNumber,
	formatHex,
	bufferFromHex,
	strSplitToArr,
	arrayBuffer2Hex,
	arrayBufferToString,
	stringToArrayBuffer,
	Base64,
	ab2hex,
	hexToBytes,
	formater4length,
	getErrMsgByCode,
	calculatXor,
	padLeft,
	padRight,
	formater4Length,
	parseResponse
}